package com.example.pufang.controller.front;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.example.common.CommonResult;
import com.example.common.PageParamRequest;
import com.example.constant.Constants;
import com.example.exception.ExceptionCodeEnum;
import com.example.pufang.pojo.Login;
import com.example.pufang.pojo.User;
import com.example.pufang.service.HouseService;
import com.example.pufang.service.LoginService;
import com.example.pufang.service.UserService;
import com.example.pufang.vo.HouseListVo;
import com.example.pufang.vo.LoginUserVo;
import com.example.utils.DESUtils;
import com.example.utils.RedisUtil;
import com.example.utils.TokenUtil;
import com.example.utils.VerifyCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/front/user")
@CrossOrigin
@Api(tags = "h5用户接口")
public class UserFrontController {

    private Logger log =  LoggerFactory.getLogger(UserFrontController.class);

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private HouseService houseService;

    @Autowired
    private LoginService loginService;

    @Operation(summary = "用户登录")
    @PostMapping("/login")
    public CommonResult<Map<String, String>> login(@RequestBody LoginUserVo user, HttpServletResponse response, HttpServletRequest request) {

        // 校验验证码
        long codeExpire = redisUtil.getExpire(Constants.LOGIN_FRONT_VERIFY_CODE + user.getPhone());
        Object verifyCode = redisUtil.get(Constants.LOGIN_FRONT_VERIFY_CODE + user.getPhone());
        if (ObjectUtils.isNotNull(verifyCode)) {

            String verifyCodeString = verifyCode.toString();
            if (!verifyCodeString.toLowerCase().equals(user.getCode().toLowerCase())) {
                return CommonResult.failed("验证码错误");
            }

        } else {
            return CommonResult.failed("请重新获取验证码");
        }

        // 查询是否已经登录，如果已经登录则直接返回
        String token = request.getHeader(Constants.HEADER_AUTHORIZATION_KEY);
        long expire = redisUtil.getExpire(Constants.HEAD_FRONT_TOKEN + token);
        if (expire > 0) {
            return CommonResult.success("已登录，请勿重复登录");
        }

        Login login = new Login();
        login.setUserPhone(user.getPhone())
                .setCreateTime(new Date());

        User userByPhone = userService.getUserByPhone(user.getPhone());

        if (ObjectUtils.isNull(userByPhone)) {
            // 保存到登录日志
            login.setSuccess(false);
            loginService.save(login);
            return CommonResult.failed("当前用户未注册，请先注册");
        }

        // 判断当前用户是否被封禁
        if (userByPhone.getIsBan()) {
            // 保存到登录日志
            login.setSuccess(false);
            login.setUserId(userByPhone.getId());
            loginService.save(login);
            return CommonResult.failed("当前账户已被封禁，请尝试联系管理员解封");
        }

        login.setUserId(userByPhone.getId());
        // 判断密码是否正确
        if (!user.getPassword().equals(DESUtils.decrypt(userByPhone.getPassword()))) {
            // 保存到登录日志
            login.setSuccess(false);
            loginService.save(login);
            return CommonResult.failed("账号或密码错误");
        }

        login.setSuccess(true)
                .setUserId(userService.getUserByPhone(user.getPhone()).getId());
        loginService.save(login);

        // 未登录则在redis数据库中插入一条token记录
        HashMap<String, String> map = new HashMap<>();
        map.put("token", tokenUtil.createFrontUserToken(user));

        return CommonResult.success(map, "登录成功");
    }

    @Operation(summary = "用户注册")
    @PostMapping("/register")
    public CommonResult<User> register(@RequestBody LoginUserVo loginUserVo){

        // 校验验证码
        long codeExpire = redisUtil.getExpire(Constants.LOGIN_FRONT_VERIFY_CODE + loginUserVo.getPhone());
        Object verifyCode = redisUtil.get(Constants.LOGIN_FRONT_VERIFY_CODE + loginUserVo.getPhone());
        if (ObjectUtils.isNotNull(verifyCode)) {

            String verifyCodeString = verifyCode.toString();
            if (!verifyCodeString.toLowerCase().equals(loginUserVo.getCode().toLowerCase())) {
                return CommonResult.failed("验证码错误");
            }

        } else {
            return CommonResult.failed("请重新获取验证码");
        }

        User user = new User();
        user.setPhone(loginUserVo.getPhone())
                .setPassword(loginUserVo.getPassword());

        if (ObjectUtils.isNotNull(userService.getUserByPhone(user.getPhone()))) {
            return CommonResult.failed("当前用户已存在，请尝试登录");
        }

        if (userService.register(user)) {
            return CommonResult.success("注册成功");
        } else  {
            return CommonResult.failed("注册失败");
        }

    }

    @Operation(summary = "获取当前用户所有信息")
    @GetMapping("/info")
    public CommonResult<User> getUserInfo(HttpServletRequest request){
        String userPhone = tokenUtil.getFrontUserPhone(request);
        if (!StringUtils.hasLength(userPhone)) {
            CommonResult.failed(ExceptionCodeEnum.UNAUTHORIZED, "请先登录");
        }
        return CommonResult.success(userService.getUserByPhone(userPhone));
    }

    @Operation(summary = "获取所有用户列表")
    @GetMapping("/getUserList")
    public List<User> getUserList() {
        return userService.list();
    }

    @Operation(summary = "修改用户信息")
    @PostMapping("/edit")
    public CommonResult<Boolean> editInfo(@RequestBody User user) {
        // 判断是否修改密码，是则重新加密保存到数据库，没有修改就不做处理
        if (!user.getPassword().equals(userService.getById(user.getId()).getPassword())) {
            user.setPassword(DESUtils.encrypt(user.getPassword()));
        }
        return CommonResult.success(userService.updateById(user));
    }

    @Operation(summary = "聊天时通过id获取用户信息")
    @GetMapping("/getUserToChat")
    public CommonResult<Map<String, Object>> getUserById(Integer receiverId, HttpServletRequest request) {

        HashMap<String, Object> map = new HashMap<>();

        User sender = userService.getUserByPhone(tokenUtil.getFrontUserPhone(request));
        if (sender.getId() == receiverId) {
            return CommonResult.failed(ExceptionCodeEnum.CHAT_SELF, "不能和自己聊天");
        }

        User user = userService.getById(receiverId);
        map.put("receiverName", user.getUsername());

        return CommonResult.success(map);
    }

    @Operation(summary = "访问首页获取信息")
    @GetMapping("/getHomePageInfo")
    public CommonResult<Map<String, Object>> getHomePageInfo(Integer userId, PageParamRequest pageParamRequest,
                                                             HttpServletRequest request) {

        HashMap<String, Object> map = new HashMap<>();

        User user = userService.getById(userId);
        map.put("userInfo", user);

        List<HouseListVo> houseListVos = houseService.getHouseListByUserId(pageParamRequest, userId);

        map.put("houseList", houseListVos);

        return CommonResult.success(map);
    }

    @Operation(summary = "获取登录验证码")
    @GetMapping("getVerifyCode")
    public void getVerifyCode(@RequestParam String phone, HttpServletRequest request,
                                                           HttpServletResponse response) {
        try {

            int width=200;
            int height=70;

            BufferedImage verifyImg=new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);

            //生成对应宽高的初始图片
            String randomText = VerifyCodeUtils.drawRandomText(width,height,verifyImg);

            //功能是生成验证码字符并加上噪点，干扰线，返回值为验证码字符
            request.getSession().setAttribute("verifyCode", randomText);

            response.setContentType("image/png");//必须设置响应内容类型为图片，否则前台不识别

            OutputStream os = response.getOutputStream(); //获取文件输出流

            ImageIO.write(verifyImg,"png",os);//输出图片流

            os.flush();
            os.close();//关闭流

            // 登录验证码存入redis用于验证
            redisUtil.set(Constants.LOGIN_FRONT_VERIFY_CODE + phone, randomText, 300L);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
